/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0.
 *
 * @Date: 2021-04-07 09:53:07
 * @LastEditTime: 2021-05-24 10:47:33
 * @Description:  This files is for uart option setting
 *
 * @Modify History:
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 */

#include "pl011_uart.h"
#include "pl011_uart_hw.h"
#include "ft_types.h"
/************************** Variable Definitions ****************************/
/*
 * The following data type is a map from an option to the offset in the
 * register to which it belongs as well as its bit mask in that register.
 */
typedef struct
{
    u32 Option;
    u32 RegisterOffset;
    u32 Mask;
} Mapping;

static Mapping OptionTable[] = {
    {FUART_OPTION_UARTEN, UARTCR_OFFSET, UARTCR_UARTEN},
    {FUART_OPTION_RXEN, UARTCR_OFFSET, UARTCR_RXE},
    {FUART_OPTION_TXEN, UARTCR_OFFSET, UARTCR_TXE},
    {FUART_OPTION_FIFOEN, UARTLCR_H_OFFSET, UARTLCR_H_FEN}};

#define FT_UART_NUM_OPITIONS (sizeof(OptionTable) / sizeof(Mapping))

void Pl011SetOptions(Pl011 *uart_p, u32 options)
{
    u32 index;
    u32 reg_value;
    FT_ASSERTVOID(uart_p != NULL);
    FT_ASSERTVOID(uart_p->is_ready == FT_COMPONENT_IS_READY);

    for (index = 0; index < FT_UART_NUM_OPITIONS; index++)
    {
        reg_value = FT_UART_READREG32(uart_p->config.base_address, OptionTable[index].RegisterOffset);

        if ((options & OptionTable[index].Option) != (u32)(0))
        {
            reg_value |= OptionTable[index].Mask;
        }
        else
        {
            reg_value &= ~OptionTable[index].Mask;
        }

        FT_UART_WRITEREG32(uart_p->config.base_address, OptionTable[index].RegisterOffset, reg_value);
    }
}

void Pl011SetSpecificOptions(Pl011 *uart_p, u32 options)
{
    u32 index;
    u32 reg_value;
    FT_ASSERTVOID(uart_p != NULL);

    for (index = 0; index < FT_UART_NUM_OPITIONS; index++)
    {
        if ((options & OptionTable[index].Option) == (u32)(0))
        {
            continue;
        }

        reg_value = FT_UART_READREG32(uart_p->config.base_address, OptionTable[index].RegisterOffset);

        /* set specific options */
        reg_value |= OptionTable[index].Mask;
        FT_UART_WRITEREG32(uart_p->config.base_address, OptionTable[index].RegisterOffset, reg_value);
    }
}

void Pl011ClearSpecificOptions(Pl011 *uart_p, u32 options)
{
    u32 index;
    u32 reg_value;
    FT_ASSERTVOID(uart_p != NULL);

    for (index = 0; index < FT_UART_NUM_OPITIONS; index++)
    {
        if ((options & OptionTable[index].Option) == (u32)(0))
        {
            continue;
        }

        reg_value = FT_UART_READREG32(uart_p->config.base_address, OptionTable[index].RegisterOffset);

        /* remove specific options */
        reg_value &= ~OptionTable[index].Mask;
        FT_UART_WRITEREG32(uart_p->config.base_address, OptionTable[index].RegisterOffset, reg_value);
    }
}
